#include "sendbsignalbp.h"
#include <stdexcept>
#include <math.h>

sendbsignalbp::sendbsignalbp() : study_speed(1.0)
{
}

sendbsignalbp::~sendbsignalbp()
{
}


//посчитать ошибку выходного слоя
void sendbsignalbp::setexpectedsignal(ntype::signal_t* signal, int size) {
  sendsignal_b_study::setexpectedsignal(signal, size);
}


void sendbsignalbp::send(double*, int)
{
  calcError();
}

#include <iostream>
void sendbsignalbp::calcError()
{
  const static ntype::signalid_t one_value     = 1.0;
  const ntype::neuronid_t  neuon_count_in_layer = getlayersize();
  const ntype::layerid_t   layer_id            = getlayercountmax() - 1;
        ntype::layerid_t   curent_layer;
  const ntype::signalid_t  signal_count_max     = p_neuron[0].getMaxSignalStudyBufferIndex();
        ntype::signal_t    exp_signal_value     = 0.0;
        ntype::signal_t    cur_signal_value     = 0.0;
        ntype::neuronid_t  start_neuron_index   = getstartneuronidforlayer(layer_id-1);
        ntype::neuronid_t  start_neuron_next_layer_index;
        ntype::neuronid_t  neuron_index;
        ntype::neuronid_t  cur_neuron_id, next_layer_cur_neuron_id;
        ntype::error_t     cur_error, neuron_error;
        ntype::synapseid_t synapse_id;
        ntype::weight_t    weight;

//clac error for output layer
  start_neuron_index = getstartneuronidforlayer(layer_id);
  for(neuron_index = 0; neuron_index < neuon_count_in_layer; neuron_index ++)
  {
    cur_neuron_id = neuron_index + start_neuron_index;
    axon &l_axon = p_neuron[cur_neuron_id].getAxon();
    neuron_error = 0.0;
    for(ntype::signalid_t cur_sig_id = 0; cur_sig_id < signal_count_max; cur_sig_id ++)
    {
       exp_signal_value = l_axon.getBStudySignal(cur_sig_id);
       cur_signal_value = l_axon.getFStudySignal(cur_sig_id);
       cur_error = (exp_signal_value - cur_signal_value) * cur_signal_value * (one_value - cur_signal_value);
       neuron_error += fabs(cur_error);
    }
//    neuron_error = neuron_error / (ntype::error_t)signal_count_max;
    p_neuron[cur_neuron_id].setStudyNeuronError(neuron_error);
    std::cout << "sendbsignalbp::calcError(...). neuron id: " << cur_neuron_id << " error: " << neuron_error << std::endl;
  }
  //clac errors for other layers
  curent_layer = layer_id;
  while(curent_layer --)
  {
      start_neuron_index = getstartneuronidforlayer(curent_layer);
      start_neuron_next_layer_index = getstartneuronidforlayer(curent_layer + 1);

      for(neuron_index = 0; neuron_index < neuon_count_in_layer; neuron_index ++)
        // neuron_index === synapse index for next layer
      {
        cur_neuron_id = neuron_index + start_neuron_index;
        synapse_id    = neuron_index;

        neuron_error = 0.0;
        for(next_layer_cur_neuron_id = 0; next_layer_cur_neuron_id < neuon_count_in_layer; next_layer_cur_neuron_id ++)
        {
          cur_error = p_neuron[start_neuron_next_layer_index + next_layer_cur_neuron_id].getStudyNeuronError();
          weight = p_neuron[start_neuron_next_layer_index + next_layer_cur_neuron_id].getSynapse(synapse_id).getWeight();
          neuron_error += cur_error * weight;
        }
        p_neuron[cur_neuron_id].setStudyNeuronError(neuron_error);
        std::cout << "sendbsignalbp::calcError(...). neuron id: " << cur_neuron_id << " error: " << neuron_error << std::endl;
      }
  }
}

//void sendbsignalbp::setoutputsignalfromaxon(int) {
//  throw std::runtime_error("not used sendbsignalbb::setoutputsignalfromaxon()");
//}

ntype::error_t sendbsignalbp::geterror()
{
   throw std::runtime_error("not used sendbsignalbb::geterror()");
}

